[iOS] Apollo CLIを使って、Swiftファイルを書き出したい
2019/07/31更新
元の投稿では複数graphqlファイルから複数swiftファイルを生成していたのですが、
それだとfragmentの扱いが面倒なので、1枚のswiftファイルに集めて生成するように変更しました。
===
こんにちは。きんくまです。
GraphQLをiOSからつなぎたくて、このブログで諏訪氏が書いた記事を参考にいろいろと試しています。 Apollo iOSを使ってGitHub API v4(GraphQL)クライアントを作る
今回は記事の中の、Apollo CLIを使ってSwift用のコードを生成する部分をカスタマイズしてみました。
できあがったもの (GitHub)
cm-tsmaeda/ApolloCLIGenSwiftSample
input/query
または input/mutation
に置いたファイルを ouput
フォルダ内に Swiftファイルとして書き出します。
やりたいこと
Apollo iOSのドキュメントを読むと、Xcodeの中でビルドのたびに、ファイルを生成していました。
ですが実案件では、そんなに型定義が変わることもないです。
なのでXcodeに組み込むのではなくて、nodeプロジェクトとして独立させて、任意のタイミングで生成したかったです。
Adding a code generation build step
また、複数のquery/mutationファイルから、名前を指定して個別のSwiftファイルを生成したいです。
Apollo CLI
Apollo CLIを使うと、Schemaファイルをダウンロードしたり、queryからSwiftファイルを生成できます。
インストール手順のところに、 -g
オプションでグローバルにインストールするように書いてあったのですが、今回はプロジェクトディレクトリにだけインストールするようにしました。
設定ファイル
src/settings.js は設定ファイルです。
authToken
の箇所を自分のトークンに置き換えてください。
// API end point const APIEndPoint = "https://api.github.com/graphql"; // トークン const authToken = "Your token is here!"; // スキーマの出力パス const schemaPath = "./output/github_schema.json"; // 入力ファイルのディレクトリ const inputDirPath = "./input"; // 出力Swiftファイルのディレクトリ const outputSwiftDirPath = "./output"; // 出力Swiftファイルの名前 const outputSwiftFileName = "GeneratedGraphQLTypes.swift"; // exports exports.APIEndPoint = APIEndPoint; exports.authToken = authToken; exports.schemaPath = schemaPath; exports.inputDirPath = inputDirPath; exports.outputSwiftDirPath = outputSwiftDirPath; exports.outputSwiftFileName = outputSwiftFileName;
Schemaファイルダウンロード
Schemaのダウンロードをします。設定ファイルを読み取って、apolloコマンドを叩いています。
download_schema.js
const exec = require('child_process').exec; const settings = require('./settings'); const mainCommand = "apollo client:download-schema"; const parameters = { "endpoint": `${settings.APIEndPoint}`, "header": `Authorization: Bearer ${settings.authToken}` }; const output = `${settings.schemaPath}`; function buildCommand(mainCommand, parameters, output){ let result = mainCommand; result += ` ${output}`; for(let key in parameters){ result += ` --${key}="${parameters[key]}"`; } return result; } let command = buildCommand(mainCommand, parameters, output); console.log(command); exec(command, (err, stdout, stderr) => { if (stderr) { console.log(stderr); } console.log(stdout); });
Swiftファイルの生成
設定ファイルを読み取って、inputフォルダ内の複数graphqlファイルから、ouputフォルダへ1枚のSwiftファイルを生成します。
src/gen_swift_files.js
const exec = require('child_process').exec; const fs = require('fs'); const settings = require('./settings'); const WORKING_FILE_PATH = "./input/temp.graphql"; function removeLastFileSeparatorIfNeeds(path) { if(path.length === 0){ return ""; } let lastChar = path.substr(-1); if(lastChar === '/'){ return path.substr(0, path.length - 1); } return path; } function buildCodeGenCommand(graphqlPath, swiftPath){ const mainCommand = "apollo client:codegen"; const parameters = { "includes": graphqlPath, "localSchemaFile": `${settings.schemaPath}`, "target": "swift", "passthroughCustomScalars" : null }; const output = swiftPath; let result = mainCommand; result += ` ${output}`; for(let key in parameters){ if(parameters[key] === null) { result += ` --${key}`; } else { result += ` --${key}="${parameters[key]}"`; } } return result; } async function executeCommand(command) { return new Promise((resolve, reject) => { exec(command, (err, stdout, stderr) => { if (stderr) { //console.log(stderr); reject(stderr); return; } //console.log(stdout); resolve(stdout); }); }); } async function removeFileIfExists(filePath) { return new Promise((resolve, reject) => { fs.access(filePath, fs.F_OK, (accessError)=>{ if (accessError) { // 存在しないので成功とする resolve(true); return; } fs.unlink(filePath, (removeError)=>{ if(removeError){ reject(removeError); return; } resolve(true); }) }); }); } async function concatGraphQLFiles(inputDir) { return new Promise(async (resolve, reject) => { let modifiedInputPath = removeLastFileSeparatorIfNeeds(inputDir); let concatCommand = `cat ${modifiedInputPath}/*.graphql > ${WORKING_FILE_PATH}`; console.log('command: ', concatCommand); await executeCommand(concatCommand); resolve(WORKING_FILE_PATH); }); } async function main() { await removeFileIfExists(WORKING_FILE_PATH); await concatGraphQLFiles(settings.inputDirPath); const swiftPath = removeLastFileSeparatorIfNeeds(settings.outputSwiftDirPath) + "/" + settings.outputSwiftFileName; const command = buildCodeGenCommand(WORKING_FILE_PATH, swiftPath); console.log(command); const result = await executeCommand(command); console.log(result); await removeFileIfExists(WORKING_FILE_PATH); } main();
使い方
Schemaファイルダウンロード
npm run schema
Swiftファイル生成
npm run codegen
注意点
Apollo CLIはよく引数やメソッド名が変わるらしいです。今回も諏訪氏の記事から4ヶ月くらいしか経っていないのですが、 --queries
オプションがDeprecated扱いになっていました。
なので、うまく動かなければ公式ドキュメントを読んでみてくださいまし。
ではでは。